using System;
using System.Collections.Generic;
using System.Text;
using PluginHandler;
using System.Data;
using System.Data.Common;

namespace DatabaseManager.Util.Executers
{

    /// <summary>
    /// Allows returning or manipulating data in a database table, which results can be displayed in the ChildQueryArea control.
    /// </summary>
    public class QueryExecuter : IExecuter
    {
        /// <summary>
        /// Describes the type of the executed query
        /// </summary>
        public enum QueryDefinition
        {
            /// <summary>
            /// No defined type.
            /// </summary>
            Undefined,
            /// <summary>
            /// Default select statement, which contains data.
            /// </summary>
            Query,
            /// <summary>
            /// Update, delete or insert statement which changes data in a database table.
            /// </summary>
            NonQuery
        }

        private IPluginHandler _pluginHandler;
        private string _commandText;
        private QueryDefinition _queryType = QueryDefinition.Undefined;
        private int _recordsAffected = -1;
        private DbException _dbError;
        private DataTable _dataTable;


        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExecuter"/> class.
        /// </summary>
        /// <param name="pluginHandler">The plugin, which holds the database connection on which the sql query is executed.</param>
        /// <param name="commandText">The sql query, which is executed.</param>
        public QueryExecuter(IPluginHandler pluginHandler, string commandText)
        {
            _pluginHandler = pluginHandler;
            _commandText = commandText;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExecuter"/> class.
        /// </summary>
        /// <param name="pluginHandler">The plugin, which holds the database connection on which the sql query is executed.</param>
        public QueryExecuter (IPluginHandler pluginHandler) :
            this(pluginHandler, string.Empty) { }

        /// <summary>
        /// Executes the query an saves the results in the given DataTable.
        /// </summary>
        /// <returns>
        /// True if the query could be executed whitout any errors.
        /// </returns>
        public bool ExecuteQuery()
        {
            return ExecuteQuery(_commandText);
        }

        /// <summary>
        /// Executes the query an saves the results in the given DataTable.
        /// </summary>
        /// <param name="commandText">The sql query, which is executed.</param>
        /// <returns>
        /// True if the query could be executed whitout any errors.
        /// </returns>
        public bool ExecuteQuery(string commandText)
        {
            bool result = false;

            if (commandText != _commandText)
            {
                _commandText = commandText;
            }

            try
            {
                IDataReader reader = _pluginHandler.DatabaseHandler.ExecuteReader(_commandText);
                
                _recordsAffected = reader.RecordsAffected;

                if (reader.RecordsAffected == -1)
                {
                    _queryType = QueryDefinition.Query;

                    _dataTable = new DataTable();
                    _dataTable.Load(
                        reader,
                        LoadOption.OverwriteChanges,
                        new FillErrorEventHandler(
                            delegate(object sender, FillErrorEventArgs e)
                            {
                                e.Continue = true;
                            }));
                    
                    //Klasse wirft bei Oracle und nicht anzeigbaren Datentypen eine Exception
                    //DataReaderAdapter dataReaderAdapter = new DataReaderAdapter();
                    //dataReaderAdapter.FillFromReader(_dataTable, reader);
                }
                else
                {
                    _queryType = QueryDefinition.NonQuery;
                }

                _dbError = null;

                reader.Close();

                result = true;
            }
            catch (DbException ex)
            {
                _dbError = ex;
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Gets the data table, which contains the results of the executed query.
        /// </summary>
        /// <value>The data table.</value>
        public DataTable DataTable
        {
            get { return _dataTable; }
        }

        /// <summary>
        /// Gets the plugin on which the sql query will be executed.
        /// </summary>
        /// <value>The plugin handler.</value>
        public IPluginHandler PluginHandler
        {
            get { return _pluginHandler; }
        }

        /// <summary>
        /// Gets the sql query, which will be executed.
        /// </summary>
        /// <value>The command text.</value>
        public string CommandText
        {
            get { return _commandText; }
        }

        /// <summary>
        /// Gets the resolved type of the query, after it was executed.
        /// </summary>
        /// <value>The type of the query.</value>
        public QueryDefinition QueryType
        {
            get { return _queryType; }
        }

        /// <summary>
        /// Gets the records, that was affected by the query, if it involves the NonQuery type.
        /// </summary>
        /// <value>The records affected.</value>
        public int RecordsAffected
        {
            get { return _recordsAffected; }
        }

        /// <summary>
        /// Gets the <class cref="DbException"/>, if there has something been going wrong.
        /// </summary>
        /// <value>The database error.</value>
        public DbException DbError
        {
            get { return _dbError; }
        }
    }
}
